/*    Copyright 2010 Tobias Marschall
 *
 *    This file is part of MoSDi.
 *
 *    MoSDi is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    MoSDi is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with MoSDi.  If not, see <http://www.gnu.org/licenses/>.
 */

package mosdi.tests;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;

import junit.framework.TestCase;
import mosdi.fa.Partition;

public class PartitionTest extends TestCase {

	public void testConstructor1() {
		Partition p = new Partition(5);
		assertEquals(1, p.blockCount());
		Iterator<Integer> iter = p.block(0).iterator();
		assertEquals(0, (int)iter.next());
		assertEquals(1, (int)iter.next());
		assertEquals(2, (int)iter.next());
		assertEquals(3, (int)iter.next());
		assertEquals(4, (int)iter.next());
		assertFalse(iter.hasNext());
	}
	
	public void testConstructor2() {
		Integer[] initialPartition = {0,80,80,1000,0,80,0,0,1000,90};
		Partition p = new Partition(Arrays.asList(initialPartition));
		assertEquals(4,p.blockCount());
		Iterator<Integer> iter = p.block(p.getBlockIndex(0)).iterator();
		assertEquals(0, (int)iter.next());
		assertEquals(4, (int)iter.next());
		assertEquals(6, (int)iter.next());
		assertEquals(7, (int)iter.next());
		assertFalse(iter.hasNext());
		int k = p.getBlockIndex(2);
		Iterable<Integer> iterable = p.block(k);
		iter = iterable.iterator();
		assertEquals(1, (int)iter.next());
		assertEquals(2, (int)iter.next());
		assertEquals(5, (int)iter.next());
		assertFalse(iter.hasNext());
		iter = p.block(p.getBlockIndex(8)).iterator();
		assertEquals(3, (int)iter.next());
		assertEquals(8, (int)iter.next());
		assertFalse(iter.hasNext());
		iter = p.block(p.getBlockIndex(9)).iterator();
		assertEquals(9, (int)iter.next());
		assertFalse(iter.hasNext());
	}
	
	private static void assertConsists(Iterable<Integer> iterable, Integer[] a, int size) {
		int n = 0;
		HashSet<Integer> set = new HashSet<Integer>(); 
		for (int i : iterable) {
			set.add(i);
			++n;
		}
		assertEquals(size,n);
		for (int i : a) {
			assertTrue(set.contains(i));
		}
	}
	
	private static void assertBlocksConsecutivelyNumbered(Partition p) {
		HashSet<Integer> blockIndices = new HashSet<Integer>();
		for (int i : p.blockIndices()) blockIndices.add(i);
		assertEquals(blockIndices.size(), p.blockCount());
		for (int i=0; i<blockIndices.size(); ++i) {
			assertTrue(blockIndices.contains(i));
		}
	}
	
	public void testSplit() {
		Partition p = new Partition(10);
		
		{
			Integer[] a = {2,2,7,3,7,2};
			Integer[] b = {0,1,4,5,6,8,9};
			int blockIdx = p.splitOff(Arrays.asList(a));
			assertEquals(2, p.blockCount());
			assertConsists(p.block(blockIdx),a,3);
			assertConsists(p.block(p.getBlockIndex(6)),b,7);
		}

		{
			Integer[] a = {3,1,9};
			Integer[] b = {0,4,5,6,8};
			Integer[] c = {2,7};
			int blockIdx = p.splitOff(Arrays.asList(a));
			assertEquals(3, p.blockCount());
			assertConsists(p.block(blockIdx),a,3);
			assertConsists(p.block(p.getBlockIndex(6)),b,5);
			assertConsists(p.block(p.getBlockIndex(2)),c,2);
		}
	}
	
	public void testSplit2() {
		Integer[] initialPartition = {109,108,107,106,105,1004,1003,1002,1001,1000};
		Partition p = new Partition(Arrays.asList(initialPartition));
		{
			Integer[] a = {0,1,4,5,6,8,9};
			Integer[] b = {2};
			Integer[] c = {3};
			Integer[] d = {7};
			int blockIdx = p.splitOff(Arrays.asList(a));
			for (int i : a) assertEquals(blockIdx, p.getBlockIndex(i));
			assertEquals(4, p.blockCount());
			assertConsists(p.block(blockIdx),a,7);
			assertConsists(p.block(p.getBlockIndex(2)),b,1);
			assertConsists(p.block(p.getBlockIndex(3)),c,1);
			assertConsists(p.block(p.getBlockIndex(7)),d,1);
			p.renumberBlocks();
			assertEquals(4, p.blockCount());
			assertConsists(p.block(p.getBlockIndex(5)),a,7);
			assertConsists(p.block(p.getBlockIndex(2)),b,1);
			assertConsists(p.block(p.getBlockIndex(3)),c,1);
			assertConsists(p.block(p.getBlockIndex(7)),d,1);
			assertBlocksConsecutivelyNumbered(p);
		}
	}
}
